#include "user_ch9329.h"
#include "user_hid.h"

#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_log.h"

void rev_task_start();

static const char *TAG = "[CH9329]";

#define UART_TX GPIO_NUM_6
#define UART_RX GPIO_NUM_5

#define CH9329_SET GPIO_NUM_4
#define CH9329_UP  GPIO_NUM_3

#define REV_BUF_SIZE (1024)

#define HEAD1 0x57
#define HEAD2 0xAB
#define ADDR 0x00

KB_STATUS kb_status;    // 键盘状态
union CFG_PKG cfg_pkg;  // 芯片配置

const uart_port_t uart_num = UART_NUM_1;    // 串口

uint8_t modifier_flag = 0;  // 控制类按键状态
static uint8_t push_key_list[6] = {0};  // 其他按键状态

void user_ch9329_init()
{
    uart_config_t uart_config = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .rx_flow_ctrl_thresh = 122,
    };
    
    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(uart_num, UART_TX, UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

    const int uart_buffer_size = (1024 * 2);
    QueueHandle_t uart_queue;
    // 在此处使用事件队列安装UART驱动程序
    ESP_ERROR_CHECK(uart_driver_install(uart_num, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));

    rev_task_start();   // 启动接收

    //////////////////////////
    ch9329_reset(); // 先复位ch9329芯片
}

void parse(CMD_ID cmd_id, uint8_t* cmd_ptr, uint8_t len)
{
    switch(cmd_id){
    case CMD_READ_INFO:{
        kb_status.usb_connect = cmd_ptr[1] ? true : false;
        kb_status.num_lock = (cmd_ptr[2] & 0x01) ? true : false;
        kb_status.caps_lock = (cmd_ptr[2] & 0x02) ? true : false;
        kb_status.scroll_lock = (cmd_ptr[2] & 0x04) ? true : false;
        kb_status.pc_sleep = (cmd_ptr[3] == 0x03) ? true : false;
        break;
    }
    case CMD_READ_KB_GENERAL_REV:{
        // ESP_LOGI(TAG, "get KB return: %2x", cmd_ptr[0]);
        break;
    }
    case CMD_SEND_MY_HID_DATA:{     // 发送HID数据回传
        break;
    }
    case CMD_READ_MY_HID_DATA:{     // 读取HID数据回传
        ESP_LOGI(TAG, "len: %d", len);
        for(int i = 0; i < len; i++){
            ESP_LOGI(TAG, "%x", cmd_ptr[i]);
        }
        break;
    }
    case CMD_GET_PARA_CFG:{         // 获取芯片配置信息
        if(len == 50){
            memset(cfg_pkg.para_cfg_buff, 0, sizeof(cfg_pkg.para_cfg_buff));  // 清空配置参数结构体
            for(int j = 0; j < 50; j++){        // 拷贝最新数据
                cfg_pkg.para_cfg_buff[j] = cmd_ptr[j];
            }
        }
        break;
    }
    case CMD_SET_PARA_CFG:{         // 配置芯片配置信息回传
        break;
    }
    default: break;
    }
}

void uart_rev_task()
{
    uint8_t* rev_data = (uint8_t*)malloc(REV_BUF_SIZE);
    REV_STATUS rev_status = REV_WAITE_HEAD1;
    while(true){
        int len = uart_read_bytes(uart_num, rev_data, (REV_BUF_SIZE - 1), 20 / portTICK_PERIOD_MS);
        if(len >= 6){
            // 可能有指令数据（至少包含头、地址、命令、长度、校验和）
            CMD_ID get_cmd_id;              // 获取到指令id
            uint8_t data_len = 0;           // 数据长度
            uint8_t wait_data_len = 0;      // 未解析数据长度
            uint8_t* data_buf = NULL;       // 数据指针
            uint8_t sum = 0;                    // 累加
            for(int i = 0; i < len; i++){   // 切换数据解析状态
                if(rev_status == REV_WAITE_HEAD1 && rev_data[i] == HEAD1){
                    rev_status = REV_WAITE_HEAD2;
                    sum += rev_data[i];
                    continue;
                }
                if(rev_status == REV_WAITE_HEAD2 && rev_data[i] == HEAD2){
                    rev_status = REV_WAITE_ADDR;
                    sum += rev_data[i];
                    continue;
                }
                if(rev_status == REV_WAITE_ADDR && rev_data[i] == ADDR){
                    rev_status = REV_WAITE_CMD;
                    sum += rev_data[i];
                    continue;
                }
                if(rev_status == REV_WAITE_CMD){
                    get_cmd_id = rev_data[i];
                    rev_status = REV_WAITE_LEN;
                    sum += rev_data[i];
                    continue;
                }
                if(rev_status == REV_WAITE_LEN){
                    wait_data_len = rev_data[i];
                    data_len = rev_data[i];
                    data_buf = (uint8_t*)malloc(wait_data_len * sizeof(uint8_t));   // 申请接收数据保存空间
                    rev_status = REV_WAITE_DATA;
                    sum += rev_data[i];
                    continue;
                }
                if(rev_status == REV_WAITE_DATA){
                    if(data_buf == NULL){
                        ESP_LOGE(TAG, "uart rev data_buf malloc fail");
                        break;
                    }
                    if(wait_data_len > 0){  // 还有数据没遍历到
                        // 保存数据
                        wait_data_len--;
                        data_buf[wait_data_len] = rev_data[i];
                        sum += rev_data[i];
                    } else{
                        rev_status = REV_WAITE_SUM;
                    }
                }
                if(rev_status == REV_WAITE_SUM){
                    // 校验
                    if(sum == rev_data[i]){
                        // ESP_LOGI(TAG, "check success");
                        parse(get_cmd_id, data_buf, data_len);
                        break;
                    }
                }
            }
            if(data_buf != NULL){
                free(data_buf); // 释放空间
            }
            rev_status = REV_WAITE_HEAD1;
        }
    }
}

void rev_task_start()
{
    xTaskCreate(uart_rev_task, "uart_rev_task", 4096, NULL, 10, NULL);
}

void ch9329_cmd_head(uint8_t* head, CMD_ID cmd_id)
{
    head[0] = HEAD1;
    head[1] = HEAD2;
    head[2] = ADDR;
    head[3] = cmd_id;
}

// 发送按键状态
void ch9329_send_key_status()
{
    uint8_t send_data[14] = {0};
    ch9329_cmd_head(send_data, CMD_SEND_KB_GENERAL_DATA);
    send_data[4] = 8;
    send_data[5] = modifier_flag;
    send_data[6] = 0;
    for(int i = 0; i < 6; i++){
        send_data[7 + i] = push_key_list[i];
    }
    uint8_t sum = 0;
    for(int i = 0; i < (sizeof(send_data) - 1); i++){
        sum = (sum + send_data[i]) & 0xff;
    }
    send_data[13] = sum;

    uart_write_bytes(uart_num, (const char*)send_data, sizeof(send_data));
}

// 清空按键状态
void ch9329_clear_key_status()
{
    modifier_flag = 0;
    memset(push_key_list, 0, sizeof(push_key_list));
    ch9329_send_key_status();
}

// 设置按键状态
void ch9329_update_key_status(uint8_t hid_num, bool push)
{
    if(hid_num <= 0x62){    // 常规按键
        if(push){
            for(int i = 0; i < 6; i++){
                if(push_key_list[i] == 0){
                    push_key_list[i] = hid_num; // 增加按键
                    break;
                }
            }
        } else{
            for(int i = 0; i < 6; i++){
                if(push_key_list[i] == hid_num){
                    push_key_list[i] = 0; // 清除按键
                }
            }
        }
    } else if(hid_num >= 0xE0 && hid_num <= 0xE7){  // 功能键
        if(push){
            modifier_flag = modifier_flag | (1U << (hid_num & 1U));
        } else{
            modifier_flag = modifier_flag & (~(1U << (hid_num & 1U)));
        }
    } else{
        return;
    }
    ch9329_send_key_status();
}

// 芯片软复位
void ch9329_reset()
{
    uint8_t send_data[6] = {0};
    ch9329_cmd_head(send_data, CMD_RESET);
    send_data[4] = 0x00;

    uint8_t sum = 0;
    for(int i = 0; i < (sizeof(send_data) - 1); i++){
        sum = (sum + send_data[i]) & 0xff;
    }
    send_data[5] = sum; 

    uart_write_bytes(uart_num, (const char*)send_data, sizeof(send_data)); 
}

// 请求芯片信息
void ch9329_get_info()
{
    uint8_t send_data[6] = {0};
    ch9329_cmd_head(send_data, CMD_GET_INFO);
    send_data[4] = 0x00;

    uint8_t sum = 0;
    for(int i = 0; i < (sizeof(send_data) - 1); i++){
        sum = (sum + send_data[i]) & 0xff;
    }
    send_data[5] = sum;   

    uart_write_bytes(uart_num, (const char*)send_data, sizeof(send_data)); 
}

// 获取芯片配置
void ch9329_get_config()
{
    uint8_t send_data[6] = {0};
    ch9329_cmd_head(send_data, CMD_GET_PARA_CFG);
    send_data[4] = 0x00;

    uint8_t sum = 0;
    for(int i = 0; i < (sizeof(send_data) - 1); i++){
        sum = (sum + send_data[i]) & 0xff;
    }
    send_data[5] = sum; 

    uart_write_bytes(uart_num, (const char*)send_data, sizeof(send_data)); 
}

// 设置芯片配置
void ch9329_set_config()
{

}
void ch9329_set_baud()  // 设置波特率
{

}

// HID上传
bool ch9329_hid_update(uint8_t* buff, uint8_t len)
{
    if(len > 63){
        ESP_LOGW(TAG, "hid update too long");
        return false;
    }
    uint8_t* send_buff = (uint8_t*)malloc((6 + len) * sizeof(uint8_t));
    ch9329_cmd_head(send_buff, CMD_SEND_MY_HID_DATA);
    send_buff[4] = len;
    memcpy(send_buff + 5, buff, len);
    uint8_t sum = 0;
    for(int i = 0; i < (5 + len); i++){
        sum = (sum + send_buff[i]) & 0xff;
    }
    send_buff[5 + len] = sum;

    bool res = uart_write_bytes(uart_num, (const char*)send_buff, 6 + len); 
    free(send_buff);
    return res;
}

/****************************************/
void test(uint8_t hid_num)
{
    ESP_LOGI(TAG, "send start");
    ch9329_clear_key_status();
    ch9329_update_key_status(hid_num, true);
    vTaskDelay(pdMS_TO_TICKS(500));
    ch9329_update_key_status(hid_num, false);
    ch9329_clear_key_status();
    ESP_LOGI(TAG, "send stop");
}
